package com.open.base.interceptor;

import com.open.base.utils.UserHolderUtils;
import com.open.common.utils.DateUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * MyBatis 拦截器，用于自动填充创建时间和更新时间字段
 * @author ：dashu03
 * @date ：2025/2/19 14:04
 * @version: 1.0.0
 */
@Component
@Slf4j
@Intercepts({
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
public class MybatisInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        Object[] args = invocation.getArgs();
        MappedStatement mappedStatement = (MappedStatement) args[0];
        Object parameter = args[1];

        String methodId = mappedStatement.getId();

        if (parameter != null) {
            String now = DateUtils.getCurrentTimeAsString();
            String user = UserHolderUtils.getLoginUser() == null ? "" : UserHolderUtils.getUserName();

            // 处理不同类型的参数
            Object actualParameter = extractActualParameter(parameter);

            if (actualParameter instanceof List) {
                // 批量操作：遍历列表中的每个对象
                List<?> list = (List<?>) actualParameter;
                for (Object item : list) {
                    fillFields(item, methodId, user, now);
                }
            } else if (actualParameter != null) {
                // 单个对象操作
                fillFields(actualParameter, methodId, user, now);
            }
            // 如果 actualParameter 为 null，说明参数无法处理，直接跳过
        }

        return invocation.proceed();
    }

    /**
     * 从各种参数类型中提取实际的业务对象
     */
    private Object extractActualParameter(Object parameter) {
        if (parameter instanceof List) {
            // 直接返回 List
            return parameter;
        } else if (parameter instanceof Map) {
            // 处理 ParamMap 或其他 Map 类型参数
            Map<?, ?> paramMap = (Map<?, ?>) parameter;

            // 尝试获取第一个非基础类型的参数值
            for (Object value : paramMap.values()) {
                if (value != null && !(value instanceof String) && !(value instanceof Number) && !(value instanceof Boolean)) {
                    return value;
                }
            }

            // 如果没找到合适的对象，返回 null
            return null;
        } else {
            // 其他情况直接返回
            return parameter;
        }
    }

    private void fillFields(Object obj, String methodId, String user, String now) {
        Class<?> clazz = obj.getClass();

        if (methodId.toLowerCase().contains("save")) {
            if (hasField(clazz, "createBy")) {
                setFieldValue(obj, "createBy", user);
            }
            if (hasField(clazz, "createTime")) {
                setFieldValue(obj, "createTime", now);
            }
        } else if (methodId.toLowerCase().contains("update")) {
            if (hasField(clazz, "updateBy")) {
                setFieldValue(obj, "updateBy", user);
            }
            if (hasField(clazz, "updateTime")) {
                setFieldValue(obj, "updateTime", now);
            }
        }
    }

    /**
     * 判断类是否包含指定字段
     */
    private boolean hasField(Class<?> clazz, String fieldName) {
        try {
            // 查找类及其父类是否存在指定字段
            clazz.getDeclaredField(fieldName);
            return true;
        } catch (NoSuchFieldException e) {
            return false;
        }
    }

    /**
     * 使用反射设置对象的字段值
     */
    private void setFieldValue(Object obj, String fieldName, Object value) {
        try {
            // 获取字段
            Field field = obj.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);  // 设置为可访问的字段
            field.set(obj, value);  // 设置字段的值
        } catch (NoSuchFieldException | IllegalAccessException e) {
            log.error("MyBatisFillInterceptor setFieldValue error", e);
        }
    }

    @Override
    public Object plugin(Object target) {
        // 为目标对象创建一个代理对象
        return Plugin.wrap(target, this);
    }

    @Override
    public void setProperties(Properties properties) {
        // 如果有必要，可以在这里读取拦截器的配置属性
    }
}
